package com.lt.flashcard.view;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.jfree.util.Log;
import org.zkoss.xel.fn.StringFns;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.metainfo.ComponentInfo;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.A;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Div;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.Textbox;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.Flashcard;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Testcase;
import com.lt.flashcard.model.entity.TestcaseMatchingData;
import com.lt.flashcard.model.entity.Testsuite;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.FlashcardService;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.LearningService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.UserService;

public class TestCtrl extends SelectorComposer<Component> {
	
	private static final long serialVersionUID = 1L;
	
	private Testsuite testsuite; //The test suite for this test
	private String imageid = "";
	private User user;
	
	private boolean isTestAll = false;
	private boolean showNotice = false;
	
	@Wire
	Div wrap_introduce; //introduction wrapper
	@Wire
	Div wrap_matching; //matching wrapper
	@Wire
	Div wrap_typing; //typing wrapper
	@Wire
	Div wrap_multi; //multi wrapper
	@Wire
	Div wrap_result; //wrap the result
	@Wire
	Label resultketqua;
	@Wire
	Label resulthang;
	
	private static final Logger log = Logger.getLogger(TestCtrl.class);
	
	@Override
	public ComponentInfo doBeforeCompose(Page page, Component parent, ComponentInfo compInfo) {
		
		AAService asrv = Repository.getInstance().getAAService();
		if(!asrv.isLogin()) {
			Utility.loginOrAccessDenied(false);
			return null;
		}
		
		String id = Executions.getCurrent().getParameter("id");
		LearningService srv = Repository.getInstance().getLearningService();
		if(StringUtils.isNotBlank(id)) {
			testsuite = srv.getTestsuiteById(id);
		}
		else {
			FlashcardSetService fcsrv = Repository.getInstance().getFlashcardSetService();
			Long fcid = Utility.parseLong(Executions.getCurrent().getParameter("fcid"));
			Long type = Utility.parseLong(Executions.getCurrent().getParameter("type"));
			FlashcardSet fcs = fcsrv.findByID(fcid);
			
			if(log.isInfoEnabled()) {
                log.info("Do testing for: " + fcid + " type: " + type);
            }
			
			if(fcs == null) {
				Utility.displayAccessDenied(false);
				return null;
			}
			
			int ttype = type == Testsuite.TYPE_TESTALL ? Testsuite.TYPE_TESTALL : Testsuite.TYPE_TESTLEARNED;
			isTestAll = ttype == Testsuite.TYPE_TESTALL;
			
			try {
				testsuite = srv.generateTestsuite(fcs, ttype);
			} catch (Exception e) {
				Log.error("Fail to generate testsuite", e);
			}
			imageid = fcs.getImage();
		}
		
		if(testsuite == null) {
			Utility.displayAccessDenied(false);
			return null;
		}
		
		if(testsuite.getTestcases().size() == 0) {
            Clients.evalJavaScript("showNotice('', 'Không có card để kiểm tra')");
        }
		
		user = Utility.getUser();
		setShowNotice(user.getUserConfig().isShowTestingPointNotice());
		
		return super.doBeforeCompose(page, parent, compInfo);
	}
	
	@Listen("onCheck=#chkNoticePoint")
	public void chkNoticePoint_check(Event event) {
		Checkbox chk = (Checkbox) event.getTarget();
		setShowNotice(!chk.isChecked());
		updateShowNotice(isShowNotice());
	}
	
	private void updateShowNotice(boolean isShow) {
		user.getUserConfig().setShowTestingPointNotice(isShow);
		user.saveUserConfig();
	}
	
	@Listen("onClick=#btnBatdau")
	public void doBatdau() {
		testsuite.setCurrentquestion(testsuite.getCurrentquestion() + 1);
		testsuite.setStatus(Testsuite.STATUS_START);
		testsuite.setTakeon(new Date());
		wrap_introduce.setVisible(false);
		updateGUITestCase();
	}
	
	/**
	 * Update the GUI
	 */
	public void updateGUITestCase() {
		Testcase tc = testsuite.getCurrentTestcase();
		if(tc == null) {
			updateGUIResult();
		}
		else {
			//Update panel
			switch(tc.getTesttype()) {
			case Testcase.TYPE_MATCHING:
				updateGUIMatching(tc);
				break;
			case Testcase.TYPE_MULTICHOICE:
				updateGUIMultichoice(tc);
				break;
			case Testcase.TYPE_TYPING:
				updateGUITyping(tc);
				break;
			}
		}
	}
	
	@Wire
	Label matchingNumber;
	@Wire
	Label matchingTotal;
	@Wire
	Label matchingLeft1;
	@Wire
	Label matchingLeft2;
	@Wire
	Label matchingLeft3;
	@Wire
	Label matchingRight1;
	@Wire
	Label matchingRight2;
	@Wire
	Label matchingRight3;
	@Wire
	Label matchingRight4;
	@Wire
	Textbox matching_result; //the result from the client
	Set<String> matching_result_order = new HashSet<String>(); //store the order after random order
	
	/**
	 * Update GUI for matching test case
	 * @param tc
	 */
	private void updateGUIMatching(Testcase tc) {
		wrap_typing.setVisible(false);
		wrap_matching.setVisible(true);
		wrap_multi.setVisible(false);
		matching_result_order.clear();
		matching_result.setValue("");
		
		List<Object> ids = new ArrayList<Object>();
		ids.add(tc.getMatching0());
		ids.add(tc.getMatching1());
		ids.add(tc.getMatching2());
		
		matchingLeft1.setValue(tc.getMatching0().getTerm());
		if(tc.getTotalwords() > 1) {
            matchingLeft2.setValue(tc.getMatching1().getTerm());
        } else {
            matchingLeft2.setValue("");
        }
		
		if(tc.getTotalwords() > 2) {
            matchingLeft3.setValue(tc.getMatching2().getTerm());
        } else {
            matchingLeft3.setValue("");
        }
		
		ids.add(tc.getMatching3());
		Object[] right = Utility.randomOrder(ids);
		
		matchingRight1.setValue(((TestcaseMatchingData)right[0]).getDefinition());
		matchingRight2.setValue(((TestcaseMatchingData)right[1]).getDefinition());
		matchingRight3.setValue(((TestcaseMatchingData)right[2]).getDefinition());
		matchingRight4.setValue(((TestcaseMatchingData)right[3]).getDefinition());
		
		for(int i = 0; i < tc.getTotalwords(); i++) {
			for(int j = 0; j < right.length; j++) {
				TestcaseMatchingData l;
				if(i == 0) {
                    l = tc.getMatching0();
                } else if(i == 1) {
                    l = tc.getMatching1();
                } else {
                    l = tc.getMatching2();
                }
				TestcaseMatchingData r = (TestcaseMatchingData) right[j];
				
				if(l.getFlashcardid() == r.getFlashcardid()) {
                    matching_result_order.add(i + "|" + j);
                }
			}
		}
		matchingNumber.setValue(String.valueOf(testsuite.getCurrentquestion() + 1));
		matchingTotal.setValue(String.valueOf(testsuite.getTotalquestion()));
		//start time counter
		Clients.evalJavaScript("$.startTestMatching(" + tc.getTotaltime() + ", " + tc.getTotalwords() + ");");
	}
	
	@Listen("onClick=#matching_finish")
	public void matching_finish() throws Exception {
		String result = matching_result.getValue();
		String[] arrResult = result.split(",");
		int time = Integer.parseInt(arrResult[0]);
		
		Testcase tc = testsuite.getCurrentTestcase();
		
		Set<String> fail = new HashSet<String>(matching_result_order); //store pair of fail, init for all fail
		Set<String> rightTerm = new HashSet<String>(); //store pair of right term
		String[] terms = new String[] { matchingLeft1.getValue(), matchingLeft2.getValue(), matchingLeft3.getValue() };
		for(int i = 1; i < arrResult.length; i++) {
			if(matching_result_order.contains(arrResult[i])) {
				fail.remove(arrResult[i]);
				rightTerm.add(terms[Utility.parseInt(arrResult[i].substring(0, arrResult[i].indexOf('|')))]);
			}
		}
		
		//update status for each matching pair
		tc.getMatching0().setResult(rightTerm.contains(tc.getMatching0().getTerm()));
		if(tc.getMatching0().isResult()) {
			tc.getMatching0().setResultTime(time);
			tc.getMatching0().setResultScore(time * 2);
		}
		tc.getMatching1().setResult(rightTerm.contains(tc.getMatching1().getTerm()));
		if(tc.getMatching1().isResult()) {
			tc.getMatching1().setResultTime(time);
			tc.getMatching1().setResultScore(time * 2);
		}
		tc.getMatching2().setResult(rightTerm.contains(tc.getMatching2().getTerm()));
		if(tc.getMatching2().isResult()) {
			tc.getMatching2().setResultTime(time);
			tc.getMatching3().setResultScore(time * 2);
		}
		tc.setStatus(fail.size() < tc.getTotalwords() ? Testcase.STATUS_RIGHT : Testcase.STATUS_WRONG);
		
		//calculate the point & coin
		if(time > tc.getTotaltime()) {
            time = 0;
        }
		int score = time * 2;
		tc.setResulttime(time);
		tc.setResultscore(score * (tc.getTotalwords() - fail.size()));
		
		//The score will be modified based on the status of flashcard
		//Update the test status for that flashcard
		LearningService lsrv = Repository.getInstance().getLearningService();
		if(tc.getMatching0().isResult()) {
            lsrv.setFlashcardPassTest(tc.getMatching0().getFlashcardid(), false, tc);
        } else {
            lsrv.setFlashcardFailTest(tc.getMatching0().getFlashcardid(), false, tc);
        }
		if(tc.getTotalwords() > 1) {
			if(tc.getMatching1().isResult()) {
                lsrv.setFlashcardPassTest(tc.getMatching1().getFlashcardid(), false, tc);
            } else {
                lsrv.setFlashcardFailTest(tc.getMatching1().getFlashcardid(), false, tc);
            }
		}
		if(tc.getTotalwords() > 2) {
			if(tc.getMatching2().isResult()) {
                lsrv.setFlashcardPassTest(tc.getMatching2().getFlashcardid(), false, tc);
            } else {
                lsrv.setFlashcardFailTest(tc.getMatching2().getFlashcardid(), false, tc);
            }
		}
		
		//update test suite
		testsuite.setResulttime(testsuite.getResulttime() + tc.getResulttime());
		testsuite.setResultscore(testsuite.getResultscore() + tc.getResultscore());
		
		//update coin
		if(tc.getResultscore() > 0) {
			user.setBlueCoin(user.getBlueCoin() + tc.getResultscore());
			user.setTotalBlueCoin(user.getTotalBlueCoin() + tc.getResultscore());
			Repository.getInstance().getUserService().save(user);
			//update the coin
			Utility.addBlueCoin(tc.getResultscore());
		}
		
		//Since this testcase contains at most 3 card, this return final score for each word
		List<Integer> rscore = new ArrayList<Integer>();
		rscore.add(tc.getMatching0().getResultScore());
		rscore.add(tc.getMatching0().isMakeupPoint() ? 1 : 0);
		rscore.add(tc.getMatching1().getResultScore());
		rscore.add(tc.getMatching1().isMakeupPoint() ? 1 : 0);
		rscore.add(tc.getMatching2().getResultScore());
		rscore.add(tc.getMatching2().isMakeupPoint() ? 1 : 0);
		
		String strRScore = StringFns.join(rscore.toArray(), ",");
		
		score = tc.getResultscore();
		//return the result or next
		String strFail = StringFns.join(fail.toArray(), ",");
		if(strFail.length() > 0) {
            strFail = String.valueOf(score) + "," + strFail;
        } else {
            strFail = String.valueOf(score);
        }
		String strRight = StringFns.join(matching_result_order.toArray(), ",");
		Clients.evalJavaScript("$.matching_result('" + strFail + "', '" + strRight + "', " + (tc.isMakeupPoint() ? 1 : 0) + ",'" + strRScore + "')");//send back to client
		if(log.isInfoEnabled()) {
            log.info("$.matching_result('" + strFail + "', '" + strRight + "', " + (tc.isMakeupPoint() ? 1 : 0) + ",'" + strRScore + "')");
        }
		if(isShowNotice() && tc.isMakeupPoint()) {
			Clients.evalJavaScript("$.showNoticePoint()");
		}
	}
	
	@Listen("onClick=.matching_next")
	public void matching_next() {
		testsuite.setCurrentquestion(testsuite.getCurrentquestion() + 1);
		updateGUITestCase();
	}
	
	@Wire
	Label multiNumber;
	@Wire
	Label multiTotal;
	@Wire
	Label multiOption0;
	@Wire
	Image multiimage0;
	@Wire
	Label multiOption1;
	@Wire
	Image multiimage1;
	@Wire
	Label multiOption2;
	@Wire
	Image multiimage2;
	@Wire
	Label multiOption3;
	@Wire
	Image multiimage3;
	@Wire
	Label multiOption4;
	@Wire
	Image multiimage4;
	@Wire
	Label multiOption5;
	@Wire
	Image multiimage5;
	@Wire
	Label multiSentence;
	@Wire
	Image multiimage;
	@Wire
	Image typingimage;
	@Wire
	Textbox multiTypingword;
	@Wire
	Textbox multi_result;
	@Wire
	Div multictn;
	
	/**
	 * Update GUI for multichoice
	 * @param tc
	 */
	private void updateGUIMultichoice(Testcase tc) {
		wrap_typing.setVisible(false);
		wrap_matching.setVisible(false);
		wrap_multi.setVisible(true);
		
		multiTypingword.setValue("");
		multi_result.setValue("");
		
		multiSentence.setValue(tc.getMultiSentence());
		if(tc.getMultiType() == Testcase.MULTI_TERM) {
            multictn.setSclass("multidefinition");
        } else {
            multictn.setSclass("");
        }
		
		//option 0
		if(tc.getMultiText0().startsWith("image:")) {
			multiimage0.setSrc(Utility.loadImageFromGridFS(tc.getMultiText0().replace("image:", ""), ""));
			multiimage0.setVisible(true);
			multiOption0.setVisible(false);
		}
		else {
			multiimage0.setVisible(false);
			multiOption0.setVisible(true);
			multiOption0.setValue(tc.getMultiText0());
		}
		//option 1
		if(tc.getMultiText1().startsWith("image:")) {
			multiimage1.setSrc(Utility.loadImageFromGridFS(tc.getMultiText1().replace("image:", ""), ""));
			multiimage1.setVisible(true);
			multiOption1.setVisible(false);
		}
		else {
			multiimage1.setVisible(false);
			multiOption1.setVisible(true);
			multiOption1.setValue(tc.getMultiText1());
		}
		//option 2
		if(tc.getMultiText2().startsWith("image:")) {
			multiimage2.setSrc(Utility.loadImageFromGridFS(tc.getMultiText2().replace("image:", ""), ""));
			multiimage2.setVisible(true);
			multiOption2.setVisible(false);
		}
		else {
			multiimage2.setVisible(false);
			multiOption2.setVisible(true);
			multiOption2.setValue(tc.getMultiText2());
		}
		//option 3
		if(tc.getMultiText3().startsWith("image:")) {
			multiimage3.setSrc(Utility.loadImageFromGridFS(tc.getMultiText3().replace("image:", ""), ""));
			multiimage3.setVisible(true);
			multiOption3.setVisible(false);
		}
		else {
			multiimage3.setVisible(false);
			multiOption3.setVisible(true);
			multiOption3.setValue(tc.getMultiText3());
		}
		//option 4
		if(tc.getMultiText4().startsWith("image:")) {
			multiimage4.setSrc(Utility.loadImageFromGridFS(tc.getMultiText4().replace("image:", ""), ""));
			multiimage4.setVisible(true);
			multiOption4.setVisible(false);
		}
		else {
			multiimage4.setVisible(false);
			multiOption4.setVisible(true);
			multiOption4.setValue(tc.getMultiText4());
		}
		//option 5
		if(tc.getMultiText5().startsWith("image:")) {
			multiimage5.setSrc(Utility.loadImageFromGridFS(tc.getMultiText5().replace("image:", ""), ""));
			multiimage5.setVisible(true);
			multiOption5.setVisible(false);
		}
		else {
			multiimage5.setVisible(false);
			multiOption5.setVisible(true);
			multiOption5.setValue(tc.getMultiText5());
		}
		
		multiNumber.setValue(String.valueOf(testsuite.getCurrentquestion() + 1));
		multiTotal.setValue(String.valueOf(testsuite.getTotalquestion()));
		if(!Utility.isEmptyString(tc.getMultiImage())) {
			multiimage.setSrc(Utility.loadImageFromGridFS(tc.getMultiImage(), ""));
			multiimage.setVisible(true);
		}
		else {
			multiimage.setVisible(false);
		}

		//int showTyping = tc.getMultiType().equals(Testcase.MULTI_TERM) ? 1 : 0;
		int showTyping = 1;
		Clients.evalJavaScript("$.startTestMulti(" + tc.getTotaltime() + ", " + showTyping + ", " + tc.getMultiIndex() + ",'" + tc.getMultiType() + "');");
	}
	
    @Wire
    Label flashcard_name;
    @Wire
    Label flashcard_term;
    @Wire
    Label flashcard_tags;
    @Wire
    Label flashcard_notes;
    @Wire
    Label flashcard_definition;
    @Wire
    Label flashcard_wordtype;
    @Wire
    Label flashcard_phonetic;
    @Wire
    Label flashcard_symnonym;
    @Wire
    Image flashcard_img;

    @Listen("onClick=.view_card")
    public void viewCard(Event event) {
        A a = (A) event.getTarget();
        String attr = (String) a.getAttribute("id");
        Testcase tc = testsuite.getCurrentTestcase();
        long id = 0;
        if (attr.equals("viewcardmulti0")) {
            id = Utility.parseLong(tc.getMultiId0());
        } else if (attr.equals("viewcardmulti1")) {
            id = Utility.parseLong(tc.getMultiId1());
        } else if (attr.equals("viewcardmulti2")) {
            id = Utility.parseLong(tc.getMultiId2());
        } else if (attr.equals("viewcardmulti3")) {
            id = Utility.parseLong(tc.getMultiId3());
        } else if (attr.equals("viewcardmulti4")) {
            id = Utility.parseLong(tc.getMultiId4());
        } else if (attr.equals("viewcardmulti5")) {
            id = Utility.parseLong(tc.getMultiId5());
        } else if (attr.equals("viewcardmatching0")) {
            id = tc.getMatching0().getFlashcardid();
        } else if (attr.equals("viewcardmatching1")) {
            id = tc.getMatching1().getFlashcardid();
        } else if (attr.equals("viewcardmatching2")) {
            id = tc.getMatching2().getFlashcardid();
        } else if (attr.equals("viewcardtyping")) {
            id = tc.getFlashcardid();
        }

        FlashcardService fsrv = Repository.getInstance().getFlashcardService();
        Flashcard flashcard = fsrv.findByID(id);
        if (flashcard == null) {
            Clients.evalJavaScript("showNotice('', 'Không tồn tại card')");
            return;
        }
        flashcard_term.setValue(flashcard.getTerm());
        flashcard_wordtype.setValue(flashcard.getWordtype());
        flashcard_phonetic.setValue(flashcard.getPhonetic());
        flashcard_notes.setValue(flashcard.getNotes());
        flashcard_symnonym.setValue(flashcard.getSymnonym());
        if (StringUtils.isNotBlank(flashcard.getDefinition())) {
            flashcard_definition.setVisible(true);
            flashcard_definition.setValue(flashcard.getDefinition());
        } else {
            flashcard_definition.setVisible(false);
        }
        flashcard_img.setVisible(StringUtils.isNotBlank(flashcard.getImage()));
        flashcard_img.setSrc(Utility.loadImageFromGridFS(flashcard.getImage(), ""));
        Clients.evalJavaScript("$.showViewCard()");
        Clients.evalJavaScript("$.updateCard()");

    }

	@Listen("onClick=#multi_check")
	public void multi_finish() throws Exception {
		String rs = multi_result.getValue();
		String[] arrRs = rs.split(",");
		int time = Utility.parseInt(arrRs[0]);
		int order = Utility.parseInt(arrRs[1]);//from 0 to 5
		
		if(log.isInfoEnabled()) {
            log.info("Multi finish time: " + time + " order: " + order);
        }
		
		Testcase tc = testsuite.getCurrentTestcase();
		int score = -1;//The score with bonus
		int realScore = -1;//The score without bonus
		
		if(order == -1) {//typing
			String term = multiTypingword.getValue().trim();
			String[] arrResult = new String[] { tc.getMultiText0().toLowerCase(), tc.getMultiText1().toLowerCase(), tc.getMultiText2().toLowerCase(), tc.getMultiText3().toLowerCase(), tc.getMultiText4().toLowerCase(), tc.getMultiText5().toLowerCase() };
			int result = Arrays.asList(arrResult).indexOf(term.toLowerCase());
			if(result == tc.getMultiIndex()) {
				score = time + time; //bonus
				realScore = time;
			}
			tc.setMultiTyping(true);
		} else if (order == tc.getMultiIndex()) {
			score = time;
			realScore = time;
		}
		
		tc.setStatus(score == -1 ? Testcase.STATUS_WRONG : Testcase.STATUS_RIGHT);
		tc.setResulttime(time > 0 ? time : 0);
		tc.setResultscore(score > 0 ? score : 0);
		
		LearningService lsrv = Repository.getInstance().getLearningService();
		if(tc.getStatus() == Testcase.STATUS_RIGHT) {
            lsrv.setFlashcardPassTest(tc.getFlashcardid(), isTestAll, tc);
        } else {
            lsrv.setFlashcardFailTest(tc.getFlashcardid(), isTestAll, tc);
        }
		//The result score is modified based on previous flashcard test status
		testsuite.setResulttime(testsuite.getResulttime() + tc.getResulttime());
		testsuite.setResultscore(testsuite.getResultscore() + tc.getResultscore());
		
		//update coin
		if(tc.getResultscore() > 0) {
			user.setBlueCoin(user.getBlueCoin() + tc.getResultscore());
			user.setTotalBlueCoin(user.getTotalBlueCoin() + tc.getResultscore());
			Repository.getInstance().getUserService().save(user);
			//update the coin
			Utility.addBlueCoin(tc.getResultscore());
		}
		
		realScore = tc.getStatus() == Testcase.STATUS_WRONG ? -1 : (tc.isMultiTyping() ? (tc.getResultscore() / 2) : tc.getResultscore());
		Clients.evalJavaScript("$.multi_result(" + realScore + ", " + tc.getMultiIndex() + ", " + (tc.isMakeupPoint() ? 1 : 0) + ")");//send back to client
		if(isShowNotice() && tc.isMakeupPoint()) {
			Clients.evalJavaScript("$.showNoticePoint()");
		}
	}
	
	@Wire
	Label typingNumber;
	@Wire
	Label typingTotal;
	@Wire
	Label typingSentence;
	@Wire
	Textbox typingResult;
	@Wire
	Textbox typing_time;
	/**
	 * Update GUI for Typing
	 * @param tc
	 */
	private void updateGUITyping(Testcase tc) {
		wrap_typing.setVisible(true);
		wrap_matching.setVisible(false);
		wrap_multi.setVisible(false);
		
		typingSentence.setValue(tc.getTypingSentence());
		typingResult.setValue("");
		
		typingNumber.setValue(String.valueOf(testsuite.getCurrentquestion() + 1));
		typingTotal.setValue(String.valueOf(testsuite.getTotalquestion()));
		
		if(!Utility.isEmptyString(tc.getTypingImage())) {
			typingimage.setSrc(Utility.loadImageFromGridFS(tc.getTypingImage(), ""));
			typingimage.setVisible(true);
		}
		else {
			typingimage.setVisible(false);
		}
		
		Clients.evalJavaScript("$.startTestTyping(" + tc.getTotaltime() + ");");
	}
	
	@Listen("onClick=#typing_check")
	public void typingResultOk() throws Exception { //update the result
		Testcase tc = testsuite.getCurrentTestcase();
		int time = Utility.parseInt(typing_time.getValue());
		LearningService lsrv = Repository.getInstance().getLearningService();
		if(typingResult.getValue().trim().toLowerCase().equals(tc.getTypingTerm().toLowerCase())) {
			tc.setResulttime(time);
			tc.setResultscore(tc.getMaxscore());
			tc.setStatus(Testcase.STATUS_RIGHT);
			lsrv.setFlashcardPassTest(tc.getFlashcardid(), isTestAll, tc);
			//update test suite
			testsuite.setResulttime(testsuite.getResulttime() + tc.getResulttime());
			testsuite.setResultscore(testsuite.getResultscore() + tc.getResultscore());
			
			//update coin
			if(tc.getResultscore() > 0) {
				user.setBlueCoin(user.getBlueCoin() + tc.getResultscore());
				user.setTotalBlueCoin(user.getTotalBlueCoin() + tc.getResultscore());
				Repository.getInstance().getUserService().save(user);
				//update the coin
				Utility.addBlueCoin(tc.getResultscore());
			}
			
			Clients.evalJavaScript("$.typing_result(" + tc.getResultscore() + ", '', " + (tc.isMakeupPoint() ? 1 : 0) + ")");
		}
		else {
			tc.setStatus(Testcase.STATUS_WRONG);
			lsrv.setFlashcardFailTest(tc.getFlashcardid(), isTestAll, tc);
			Clients.evalJavaScript("$.typing_result(-1, '" + tc.getTypingTerm() + "', 0)");
		}
		if(isShowNotice() && tc.isMakeupPoint()) {
			Clients.evalJavaScript("$.showNoticePoint()");
		}
	}
	
	@Wire
	Label resultNumber;
	@Wire
	Label resultTotal;
	@Wire
	Label resultCoin;
	
	/**
	 * Display the result of the test
	 */
	private void updateGUIResult() {
		wrap_result.setVisible(true);
		wrap_typing.setVisible(false);
		wrap_matching.setVisible(false);
		wrap_multi.setVisible(false);
		
		//calculate the result
		List<String> arrMulti = new ArrayList<String>();
		List<String> arrMatching = new ArrayList<String>();
		List<String> arrTyping = new ArrayList<String>();
		int rsTotal = testsuite.getTotalwords();
		int rsNumber = 0;
		
		FlashcardService fcs = Repository.getInstance().getFlashcardService();
		UserService usrv = Repository.getInstance().getUserService();
		
		for(Testcase tc : testsuite.getTestcases()) {
			switch (tc.getTesttype()) {
			case Testcase.TYPE_MATCHING:
				arrMatching.add(tc.getMatching0().getTerm() + (tc.getMatching0().isResult() ? "|1" : "|0"));
				if(tc.getMatching0().isResult()) {
                    rsNumber += 1;
                }
				if(tc.getTotalwords() > 1) {
					arrMatching.add(tc.getMatching1().getTerm() + (tc.getMatching1().isResult() ? "|1" : "|0"));
					if(tc.getMatching1().isResult()) {
                        rsNumber += 1;
                    }
				}
				if(tc.getTotalwords() > 2) {
					arrMatching.add(tc.getMatching2().getTerm() + (tc.getMatching2().isResult() ? "|1" : "|0"));
					if(tc.getMatching2().isResult()) {
                        rsNumber += 1;
                    }
				}
				break;
			case Testcase.TYPE_MULTICHOICE:
				Flashcard fc = fcs.findByID(tc.getFlashcardid());
				arrMulti.add(fc.getTerm() + (tc.getStatus() == Testcase.STATUS_RIGHT ? "|1" : "|0"));
				if(tc.getStatus() == Testcase.STATUS_RIGHT) {
                    rsNumber += 1;
                }
				break;
			case Testcase.TYPE_TYPING:
				arrTyping.add(tc.getTypingTerm() + (tc.getStatus() == Testcase.STATUS_RIGHT ? "|1" : "|0"));
				if(tc.getStatus() == Testcase.STATUS_RIGHT) {
                    rsNumber += 1;
                }
				break;
			}
		}
		resultCoin.setValue(String.valueOf(testsuite.getResultscore()));
		resultNumber.setValue(String.valueOf(rsNumber));
		resultTotal.setValue(String.valueOf(rsTotal));
		
		//save to database
		LearningService lsrv = Repository.getInstance().getLearningService();
		testsuite.setStatus(Testsuite.STATUS_FINISH);
		testsuite.setResultrightwords(rsNumber);
		lsrv.saveTestresult(testsuite);
		
		//TODO optimize this, currently save user many place
		int newrank = usrv.getRank(user);
		int dt = user.getRank() - newrank;
		
		if(dt != 0) {
			user.setRank(newrank);
			usrv.save(user);
		}
		
		resultketqua.setValue(newrank + "%");
		if(dt == 0) {
			resulthang.setSclass("hang_giu");
            resulthang.setValue("giữ hạng");
		}
		else if(dt > 0) {
			resulthang.setSclass("hang_tang");
			resulthang.setValue(dt + "%");
		}
		else {
			dt = -dt;
			resulthang.setSclass("hang_giam");
			resulthang.setValue(dt + "%");
		}
		
		Clients.evalJavaScript("$.showTestResultMatching('" + StringFns.join(arrMatching.toArray(), ",") + "')");
		Clients.evalJavaScript("$.showTestResultMulti('" + StringFns.join(arrMulti.toArray(), ",") + "')");
		Clients.evalJavaScript("$.showTestResultTyping('" + StringFns.join(arrTyping.toArray(), ",") + "')");
		//update the result
		Clients.evalJavaScript("$.showTestResult();");
	}
	
	/**
	 * Exit the test
	 */
	@Listen("onClick=.btnClose")
	public void btnClose_click() {
		Utility.redirect("dashboard.zul", true);
	}
	
	public Testsuite getTestsuite() {
		return testsuite;
	}

	public void setTestsuite(Testsuite testsuite) {
		this.testsuite = testsuite;
	}

	public String getImageid() {
		return imageid;
	}

	public void setImageid(String imageid) {
		this.imageid = imageid;
	}

	/**
	 * @return the showNotice
	 */
	public boolean isShowNotice() {
		return showNotice;
	}

	/**
	 * @param showNotice the showNotice to set
	 */
	public void setShowNotice(boolean showNotice) {
		this.showNotice = showNotice;
	}
}
